home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / dnsconf / primary.c < prev    next >
C/C++ Source or Header  |  1996-07-27  |  12KB  |  532 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <limits.h>
  5. #include "dnsconf.h"
  6. #include "internal.h"
  7. #include "../netconf/netconf.h"
  8. #include "dnsconf.m"
  9.  
  10. static DNSCONF_HELP_FILE help_primary("primary");
  11.  
  12. /*
  13.     Used to read back an existing configuration
  14. */
  15. PUBLIC PRIMARY::PRIMARY(
  16.     const char *_domain,
  17.     const char *_file,    // File used to store the configuration
  18.     const char *named_dir)    // Default directory for configuration files
  19. {
  20.     domain.setfrom (_domain);
  21.     file.setfrom (_file);
  22.     origins.read (named_dir,_file,_domain);
  23.     domainv.setfrom (_domain);
  24.     isrev = 0;
  25. }
  26.  
  27. PUBLIC PRIMARY::PRIMARY()
  28. {
  29.     isrev = 0;
  30. }
  31. /*
  32.     Update the domain name from the visual one.
  33. */
  34. PUBLIC VIRTUAL void PRIMARY::setfromv()
  35. {
  36.     domain.setfrom (domainv);
  37. }
  38.  
  39. /*
  40.     Used to read back an existing configuration
  41. */
  42. PUBLIC PRIMARY_REV::PRIMARY_REV(
  43.     const char *_domain,
  44.     const char *_file,    // File used to store the configuration
  45.     const char *named_dir)    // Default directory for configuration files
  46.     : PRIMARY(_domain,_file,named_dir)
  47. {
  48.     IP_ADDR ipa;
  49.     ipa.setfrom (_domain);
  50.     ipa.reverse ();
  51.     ipa.shift();
  52.     domainv.setfrom (ipa.get());
  53.     isrev = 1;
  54. }
  55.  
  56. PUBLIC PRIMARY_REV::PRIMARY_REV()
  57. {
  58. }
  59.  
  60. /*
  61.     Update the domain name from the visual one.
  62. */
  63. PUBLIC void PRIMARY_REV::setfromv()
  64. {
  65.     IP_ADDR ipa;
  66.     ipa.setfrom (domainv.get());
  67.     char buf[30];
  68.     ipa.setrev (buf);
  69.     domain.setfrom (buf);
  70. }
  71.  
  72. /*
  73.     Return != if any component of the PRIMARY was modified
  74. */
  75. PUBLIC int PRIMARY::was_modified()
  76. {
  77.     int ret = ARRAY_OBJ::was_modified();
  78.     if (!ret){
  79.         ret = origins.was_modified();
  80.     }
  81.     return ret;
  82. }
  83.  
  84. /*
  85.     Return != 0 if the PRIMARY describe the reverse mapping of an
  86.     IP network (x.y,z.in-addr.arpa)
  87. */
  88. PUBLIC VIRTUAL int PRIMARY::is_reverse()
  89. {
  90.     return 0;
  91. }
  92. /*
  93.     Return != 0 if the PRIMARY describe the reverse mapping of an
  94.     IP network (x.y,z.in-addr.arpa)
  95. */
  96. PUBLIC int PRIMARY_REV::is_reverse()
  97. {
  98.     return 1;
  99. }
  100.  
  101. /*
  102.     Locate all IP number in use in a domain.
  103.     Return the number added to adrs
  104. */
  105. PUBLIC int PRIMARY::getalladr(IP_ADDRS &adrs)
  106. {
  107.     int ret = 0;
  108.     for (int i=0; i<origins.getnb(); i++){
  109.         ret += origins.getitem(i)->getalladr(adrs);
  110.     }
  111.     return ret;
  112. }
  113.  
  114. /*
  115.     Find the first record of a certain type in the PRIMARY
  116.     Returne NULL if not found.
  117. */
  118. PRIVATE RECORD *PRIMARY::getfirst(RECORD_TYPE rtype)
  119. {
  120.     RECORD *ret = NULL;
  121.     for (int i=0; ret == NULL && i<origins.getnb(); i++){
  122.         ORIGIN *ori = origins.getitem(i);
  123.         for (int o=0; o<ori->tbrec.getnb(); o++){
  124.             RECORD *rec = ori->tbrec.getitem(o);
  125.             if (rec->is(rtype)){
  126.                 ret = rec;
  127.                 break;
  128.             }
  129.         }
  130.     }
  131.     return ret;
  132. }
  133. /*
  134.     Find the (first) soa record of a primary
  135.     Return NULL if it can be found.
  136. */
  137. PROTECTED RECORD_IN_SOA *PRIMARY::getsoa()
  138. {
  139.     return (RECORD_IN_SOA*)getfirst(RTYPE_SOA);
  140. }
  141. /*
  142.     Find all the NS records for a name.
  143.     Return the number of record found.
  144. */
  145. PUBLIC int PRIMARY::getns(
  146.     SSTRING &dom,
  147.     RECORDS &recs)
  148. {
  149.     FQHOST fq (dom);
  150.     return locate_left (fq,RTYPE_NS,recs);
  151. }
  152. /*
  153.     Find all the NS records for a name.
  154.     Return the number of record found.
  155. */
  156. PUBLIC int PRIMARY::getns(
  157.     SSTRING &dom,
  158.     SSTRINGS &strs)
  159. {
  160.     RECORDS recs;
  161.     int nb = getns (dom,recs);
  162.     for (int i=0; i<nb; i++){
  163.         RECORD_IN_NS *ns = (RECORD_IN_NS*)recs.getitem(i);
  164.         strs.add (new SSTRING (ns->ns));
  165.     }
  166.     return nb;
  167. }
  168. /*
  169.     Find all the MX records for name.
  170.     Return the number of record found.
  171. */
  172. PUBLIC int PRIMARY::getmx(
  173.     SSTRING &dom,
  174.     RECORDS &recs)
  175. {
  176.     FQHOST fq (dom);
  177.     return locate_left (fq,RTYPE_MX,recs);
  178. }
  179. /*
  180.     Find all the MX records for a name.
  181.     Return the number of record found.
  182. */
  183. PUBLIC int PRIMARY::getmx(
  184.     SSTRING &dom,
  185.     SSTRINGS &strs)
  186. {
  187.     RECORDS recs;
  188.     int nb = getmx (dom,recs);
  189.     for (int i=0; i<nb; i++){
  190.         RECORD_IN_MX *mx = (RECORD_IN_MX*)recs.getitem(i);
  191.         strs.add (new SSTRING (mx->servname));
  192.     }
  193.     return nb;
  194. }
  195. /*
  196.     Find all the A records for a name.
  197.     Return the number of record found.
  198. */
  199. PUBLIC int PRIMARY::geta(
  200.     SSTRING &dom,
  201.     RECORDS &recs)
  202. {
  203.     FQHOST fq (dom);
  204.     return locate_left (fq,RTYPE_A,recs);
  205. }
  206.  
  207. /*
  208.     Find all the A records for a name.
  209.     Return the number of record found.
  210. */
  211. PUBLIC int PRIMARY::geta(
  212.     SSTRING &dom,
  213.     IP_ADDRS &adrs)
  214. {
  215.     RECORDS recs;
  216.     int nb = geta (dom,recs);
  217.     for (int i=0; i<nb; i++){
  218.         RECORD_IN_A *a = (RECORD_IN_A*)recs.getitem(i);
  219.         adrs.add (new IP_ADDR (a->addr));
  220.     }
  221.     return nb;
  222. }
  223. /*
  224.     Find the CNAME record for a name.
  225.     Return -1 if not found. cname will be empty.
  226. */
  227. PUBLIC int PRIMARY::getcname(
  228.     SSTRING &dom,
  229.     SSTRING &cname)
  230. {
  231.     FQHOST fq (dom);
  232.     RECORDS recs;
  233.     int nb = locate_left (fq,RTYPE_CNAME,recs);
  234.     cname.setfrom ("");
  235.     int ret = -1;
  236.     if (nb > 0){
  237.         RECORD_IN_CNAME *a = (RECORD_IN_CNAME*)recs.getitem(0);
  238.         cname.setfrom (a->name);
  239.         ret = 0;
  240.     }
  241.     return ret;
  242. }
  243.  
  244. /*
  245.     Increment if needed the serial number of the SOA
  246.     This function may be called several time. The serial number
  247.     will be incremented only once per session though.
  248. */
  249. PUBLIC void PRIMARY::updatesoa()
  250. {
  251.     if (origins.was_modified()){
  252.         RECORD_IN_SOA *soa = getsoa();
  253.         if (soa != NULL) soa->update(domain.get());
  254.     }
  255. }
  256. /*
  257.     Write the records of the domain and the entry in named.boot
  258.     Return -1 if any error.
  259. */
  260. PUBLIC int PRIMARY::write (FILE *fout, const char *named_dir) const
  261. {
  262.     int ret = origins.save (named_dir,file.get());
  263.     fprintf (fout,"primary\t%s\t%s\n",domain.get(),file.get());
  264.     return ret;
  265. }
  266.  
  267.  
  268. /*
  269.     Add a record in the PRIMARY.
  270.     The record is record relative to the main origin of the primary.
  271. */
  272. PUBLIC void PRIMARY::addrec (RECORD *rec)
  273. {
  274.     if (origins.getnb()==0){
  275.         ORIGIN *ori = new ORIGIN(domain.get());
  276.         origins.add (ori);
  277.     }
  278.     origins.getitem(0)->tbrec.add (rec);
  279. }
  280.  
  281.  
  282. /*
  283.     Edit the basic specs of a domain.
  284.     Return -1 if the user abort edition
  285.     Return  0 if the user accepted the changes
  286.     Return  1 if the user wish to delete this domain.
  287. */
  288. PUBLIC int PRIMARY::edit(DNS &dns)
  289. {
  290.     THISHOST thost;
  291.     DIALOG dia;
  292.     dia.newf_str (isrev ? MSG_U(F_NETNUM,"Network number")
  293.         : MSG_U(F_DOMAIN,"Domain"),domainv);
  294.     RECORD_IN_SOA *soa = getsoa();
  295.     SSTRINGS rns;
  296.     if (getns(domain,rns) == 0){
  297.         rns.add (new SSTRING (thost.getname1()));
  298.     }
  299.     /* #Specification: dnsconf / main ns records of the domain
  300.         dnsconf allows the specification of up to 3 NS
  301.         record for a primary.
  302.     */
  303.     while (rns.getnb() < 3) rns.add (new SSTRING);
  304.     SSTRINGS rmx;
  305.     if (getmx(domain,rmx) == 0){
  306.         rmx.add (new SSTRING (thost.getname1()));
  307.     }
  308.     /* #Specification: dnsconf / main mx records of the domain
  309.         dnsconf allows the specification of up to 3 MX
  310.         records for a primary.
  311.     */
  312.     while (rmx.getnb() < 3) rmx.add (new SSTRING);
  313.     if (soa == NULL) soa = new RECORD_IN_SOA;
  314.     dia.newf_str (MSG_U(F_MAINSERV,"Main server"),soa->machine);
  315.     dia.newf_str (MSG_U(F_ADMINMAIL,"Administrator email"),soa->admin);
  316.  
  317.     dia.newf_title ("",MSG_R(F_DNSADV));
  318.     int i;
  319.     for (i=0; i<rns.getnb(); i++){
  320.         dia.newf_str ("",*(rns.getitem(i)));
  321.     }
  322.  
  323.     dia.newf_title ("",MSG_R(F_EMAILADV));
  324.     for (i=0; i<rmx.getnb(); i++){
  325.         dia.newf_str ("",*(rmx.getitem(i)));
  326.     }
  327.     dia.newf_title ("",MSG_U(F_SECREQ,"Secondaries requirements"));
  328.     dia.newf_str (MSG_U(F_REFRESH,"Refresh"),soa->refresh);
  329.     dia.newf_str (MSG_U(F_RETRY,"Retry"),soa->retry);
  330.     dia.newf_str (MSG_U(F_EXPIRE,"Expire"),soa->expire);
  331.     dia.newf_title ("",MSG_U(F_EVERYHOSTS,"Every hosts requirements"));
  332.     dia.newf_str (MSG_U(F_TTL,"Time to live"),soa->default_ttl);
  333.     int ret = -1;
  334.     int nof = 0;
  335.     while (1){
  336.         MENU_STATUS status = dia.edit (
  337.              MSG_U(T_PRIMSPEC,"Primary specification")
  338.             ,MSG_U(I_PRIMSPEC,"You must enter a domain name\n")
  339.             ,help_primary.getpath()
  340.             ,nof
  341.             ,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL);
  342.         if (status == MENU_CANCEL || status == MENU_ESCAPE){
  343.             break;
  344.         }else if (status == MENU_DEL){
  345.             if (xconf_areyousure(MSG_U(Q_DELPRIMARY
  346.                 ,"Confirm deletion of a domain"))){
  347.                 ret = 1;
  348.                 break;
  349.             }
  350.         }else{
  351.             if (domainv.is_empty()){
  352.                 xconf_error(MSG_U(E_NODOMAIN,"Fill at least the domain\n"
  353.                     "and the first IP address"));
  354.             }else{
  355.                 setfromv();
  356.                 if (getsoa()==NULL) addrec (soa);
  357.                 /* #Specification: dnsconf / primary / record file
  358.                     dnsconf use the domain name as the file name
  359.                     which will contain the record.
  360.  
  361.                     You can change the name in /etc/named.boot and dnsconf
  362.                     will use this one instead.
  363.                 */
  364.                 if (file.is_empty) file.setfrom (domainv);
  365.                 dns.setmx (domain,rmx);
  366.                 dns.setns (domain,rns);
  367.                 setmodified();
  368.                 ret = 0;
  369.                 break;
  370.             }
  371.         }
  372.     }
  373.     if (ret != 0) dia.restore();
  374.     return ret;
  375. }
  376.  
  377.  
  378.  
  379. PUBLIC PRIMARY *PRIMARYS::getitem (int no) const
  380. {
  381.     return (PRIMARY*)ARRAY::getitem(no);
  382. }
  383.  
  384. /*
  385.     Locate all IP number in use in all domain of this DNS.
  386.     Return the number added to adrs
  387. */
  388. PUBLIC int PRIMARYS::getalladr(IP_ADDRS &adrs)
  389. {
  390.     int ret = 0;
  391.     for (int i=0; i<getnb(); i++){
  392.         ret += getitem(i)->getalladr(adrs);
  393.     }
  394.     return ret;
  395. }
  396. /*
  397.     Get a PRIMARY for a fully qualified host.
  398.     Get the primary that is the closest to the hostname
  399.     (ie: x.y.z.com will select y.z.com instead of z.com if both
  400.      domain are defined in this DNS).
  401.     Return NULL if not found.
  402. */
  403. PUBLIC PRIMARY *PRIMARYS::getitem(
  404.     FQHOST &fq,
  405.     char *hostpart,
  406.     int dontitself)        // if dontitself != 0
  407.                 // && fq is itself a domain
  408.                 // don't select it
  409. {
  410.     /* #Specification: dnsconf / matching a primary / closest
  411.         When trying to dispatch information about a host
  412.         in the DNS, dnsconf try to find the primary which
  413.         has the closest match. This means that if a DNS
  414.         is a primary for x.y.com and y.com, and dnsconf
  415.         dispatch info about the host host.x.y.com, it will
  416.         select the domain x.y.com.
  417.  
  418.         On the other end, host.w.y.com will be dispatch
  419.         in the domain y.com.
  420.     */
  421.     PRIMARY *ret = NULL;
  422.     int minlevel = 100;
  423.     if (hostpart != NULL) hostpart[0] = '\0';
  424.     for (int i=0; i<getnb(); i++){
  425.         PRIMARY *pri = getitem(i);
  426.         char tmp[200];
  427.         int level = fq.is_member(pri->domain.get(),tmp);
  428.         if (level > 0 && level < minlevel){
  429.             if (!dontitself || strcmp(tmp,"@")!=0){
  430.                 ret = pri;
  431.                 minlevel = level;
  432.                 if (hostpart != NULL) strcpy (hostpart,tmp);
  433.             }
  434.         }
  435.     }
  436.     return ret;
  437. }
  438.  
  439. /*
  440.     Get a PRIMARY for a fully qualified host.
  441.     Get the primary that is the closest to the hostname
  442.     (ie: x.y.z.com will select y.z.com instead of z.com if both
  443.      domain are defined in this DNS).
  444.     Return NULL if not found.
  445. */
  446. PUBLIC PRIMARY *PRIMARYS::getitem(FQHOST &fq, char *hostpart)
  447. {
  448.     return getitem (fq,hostpart,0);
  449. }
  450.  
  451.  
  452. PUBLIC int PRIMARYS::write (FILE *fout, const char *named_dir) const
  453. {
  454.     int ret = 0;
  455.     for (int i=0; i<getnb(); i++){
  456.         if (getitem(i)->write(fout,named_dir) == -1) ret = -1;
  457.     }
  458.     return ret;
  459. }
  460.  
  461. PUBLIC VIRTUAL PRIMARY *PRIMARYS::new_PRIMARY()
  462. {
  463.     return new PRIMARY;
  464. }
  465. PUBLIC PRIMARY *PRIMARYS_REV::new_PRIMARY()
  466. {
  467.     return new PRIMARY_REV;
  468. }
  469.  
  470. static int cmp_by_name (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2)
  471. {
  472.     PRIMARY *s1 = (PRIMARY*)o1;
  473.     PRIMARY *s2 = (PRIMARY*)o2;
  474.     return s1->domainv.cmp(s2->domainv);
  475. }
  476.  
  477.  
  478. /*
  479.     Present the list of primarys. Show selectivly the
  480.     standard domain primaris or the reverse mapping primarys.
  481. */
  482. PUBLIC void PRIMARYS::edit(DNS &dns)
  483. {
  484.     int choice=0;
  485.     while (1){
  486.         int nb = getnb();
  487.         /* #Specification: domains / edition / sorting
  488.             Domain are always sorted before being presented. This changes
  489.             the ordering in /etc/named.boot.
  490.         */
  491.         sort(cmp_by_name);
  492.         DIALOG dia;
  493.         for (int i=0; i<nb; i++){
  494.             PRIMARY *pri = getitem(i);
  495.             dia.new_menuitem (" ",pri->domainv);
  496.         }
  497.         dia.addwhat (MSG_U(I_ADDPRIM,"add one primary spec"));
  498.         MENU_STATUS code = dia.editmenu(
  499.             MSG_U(T_PRIMARYS,"Primarys")
  500.             ,MSG_U(I_PRIMARYS
  501.                 ,"You are allowed to edit/add/remove primaries\n")
  502.             ,help_primary
  503.             ,choice,0);
  504.         if (code == MENU_QUIT || code == MENU_ESCAPE){
  505.             break;
  506.         }else if (code == MENU_ADD){
  507.             PRIMARY *pri = new_PRIMARY();
  508.             add (pri);
  509.             if (pri->edit(dns) != 0){
  510.                 remove_del (pri);
  511.             }else{
  512.                 /* #Specification: dnsconf / new primary / host info
  513.                     Whenever we add a new primary, we
  514.                     try to update the basic host information
  515.                     of this host so the DNS will be
  516.                     automaticly current.
  517.                 */
  518.                 netconf_updatedns();
  519.                 dns.write();
  520.             }
  521.         }else if (choice >= 0 && choice < nb){
  522.             PRIMARY *pri = getitem(choice);
  523.             int ok = pri->edit(dns);
  524.             if (ok >= 0){
  525.                 if (ok == 1) remove_del(pri);
  526.                 dns.write();
  527.             }
  528.         }
  529.     }
  530.  
  531. }
  532.